home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / win / X11 / wintext.c < prev    next >
C/C++ Source or Header  |  1993-01-16  |  9KB  |  347 lines

  1. /*    SCCS Id: @(#)wintext.c    3.1    92/3/7
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * File for dealing with text windows.
  7.  * 
  8.  *     + No global functions.
  9.  */
  10. #include <X11/Intrinsic.h>
  11. #include <X11/StringDefs.h>
  12. #include <X11/Shell.h>
  13. #include <X11/Xos.h>
  14. #include <X11/Xaw/AsciiText.h>
  15. #include <X11/Xaw/Cardinals.h>
  16.  
  17. #include "hack.h"
  18. #include "winX.h"
  19.  
  20.  
  21. #define TRANSIENT_TEXT    /* text window is a transient window (no positioning) */
  22.  
  23. static const char text_translations[] =
  24.     "#override\n\
  25.      <BtnDown>: dismiss_text()\n\
  26.      <Key>: key_dismiss_text()";
  27.  
  28. /*
  29.  * Callback used for all text windows.  The window is poped down on any key
  30.  * or button down event.  It is destroyed if the main nethack code is done
  31.  * with it.
  32.  */
  33. /*ARGSUSED*/
  34. void
  35. dismiss_text(w, event, params, num_params)
  36.     Widget w;
  37.     XEvent *event;
  38.     String *params;
  39.     Cardinal *num_params;
  40. {
  41.     struct xwindow *wp;
  42.     struct text_info_t *text_info;
  43.     Widget popup = XtParent(w);
  44.  
  45.     wp = find_widget(w);
  46.     text_info = wp->text_information;
  47.  
  48.     nh_XtPopdown(popup);
  49.  
  50.     if (text_info->blocked) {
  51.     exit_x_event = TRUE;
  52.     } else if (text_info->destroy_on_ack) {
  53.     destroy_text_window(wp);
  54.     }
  55. }
  56.  
  57. /* Dismiss when a non-modifier key pressed. */
  58. void
  59. key_dismiss_text(w, event, params, num_params)
  60.     Widget w;
  61.     XEvent *event;
  62.     String *params;
  63.     Cardinal *num_params;
  64. {
  65.     char ch = key_event_to_char((XKeyEvent *) event);
  66.     if (ch) dismiss_text(w, event, params, num_params);
  67. }
  68.  
  69. /* ARGSUSED */
  70. void
  71. add_to_text_window(wp, attr, str)
  72.     struct xwindow *wp;
  73.     int attr;    /* currently unused */
  74.     const char *str;
  75. {
  76.     struct text_info_t *text_info = wp->text_information;
  77.     int width;
  78.  
  79.     append_text_buffer(&text_info->text, str, FALSE);
  80.  
  81.     /* Calculate text width and save longest line */
  82.     width = XTextWidth(text_info->fs, str, (int) strlen(str));
  83.     if (width > text_info->max_width)
  84.     text_info->max_width = width;
  85. }
  86.  
  87. void
  88. display_text_window(wp, blocking)
  89.     struct xwindow *wp;
  90.     boolean blocking;
  91. {
  92.     struct text_info_t *text_info;
  93.     Arg args[8];
  94.     Cardinal num_args;
  95.     Dimension width, height;
  96.     int nlines;
  97.  
  98.     text_info = wp->text_information;
  99.     width  = text_info->max_width + text_info->extra_width;
  100.     text_info->blocked = blocking;
  101.     text_info->destroy_on_ack = FALSE;
  102.  
  103.     /*
  104.      * Calculate the number of lines to use.  First, find the number of
  105.      * lines that would fit on the screen.  Next, remove four of these
  106.      * lines to give room for a possible window manager titlebar (some
  107.      * wm's put a titlebar on transient windows).  Make sure we have
  108.      * _some_ lines.  Finally, use the number of lines in the text if
  109.      * there are fewer than the max.
  110.      */
  111.     nlines = (XtScreen(wp->w)->height - text_info->extra_height) /
  112.             (text_info->fs->ascent + text_info->fs->descent);
  113.     nlines -= 4;
  114.     if (nlines <= 0) nlines = 1;
  115.  
  116.     if (nlines > text_info->text.num_lines)
  117.     nlines = text_info->text.num_lines;
  118.  
  119.     /* Font height is ascent + descent. */
  120.     height = (nlines * (text_info->fs->ascent + text_info->fs->descent))
  121.                             + text_info->extra_height;
  122.  
  123.     num_args = 0;
  124.  
  125.     if (nlines < text_info->text.num_lines) {
  126.     /* add on width of scrollbar.  Really should look this up,
  127.      * but can't until the window is realized.  Chicken-and-egg problem.
  128.      */
  129.     width += 20;
  130.     }
  131.  
  132.     if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */
  133.     /* Back off some amount - we really need to back off the scrollbar */
  134.     /* width plus some extra.                       */
  135.     width = XtScreen(wp->w)->width - 20;
  136.     }
  137.     XtSetArg(args[num_args], XtNstring, text_info->text.text);    num_args++;
  138.     XtSetArg(args[num_args], XtNwidth,  width);            num_args++;
  139.     XtSetArg(args[num_args], XtNheight, height);        num_args++;
  140.     XtSetValues(wp->w, args, num_args);
  141.  
  142. #ifdef TRANSIENT_TEXT
  143.     XtRealizeWidget(wp->popup);
  144.     positionpopup(wp->popup);
  145. #endif
  146.  
  147.     nh_XtPopup(wp->popup, XtGrabNone, wp->w);
  148.  
  149.     /* Kludge alert.  Scrollbars are not sized correctly by the Text widget */
  150.     /* if added before the window is displayed, so do it afterward. */
  151.     num_args = 0;
  152.     if (nlines < text_info->text.num_lines) {    /* add vert scrollbar */
  153.     XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollAlways);
  154.                                 num_args++;
  155.     }
  156.     if (width >= (Dimension) (XtScreen(wp->w)->width-20)) {    /* too wide */
  157.     XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollAlways);
  158.                                 num_args++;
  159.     }
  160.     if (num_args) XtSetValues(wp->w, args, num_args);
  161.  
  162.     /* We want the user to acknowlege. */
  163.     if (blocking) {
  164.     (void) x_event(EXIT_ON_EXIT);
  165.     nh_XtPopdown(wp->popup);
  166.     }
  167. }
  168.  
  169.  
  170. void
  171. create_text_window(wp)
  172.     struct xwindow *wp;
  173. {
  174.     struct text_info_t *text_info;
  175.     Arg args[8];
  176.     Cardinal num_args;
  177.     Position top_margin, bottom_margin, left_margin, right_margin;
  178.  
  179.     wp->type = NHW_TEXT;
  180.  
  181.     wp->text_information = text_info = 
  182.             (struct text_info_t *) alloc(sizeof(struct text_info_t));
  183.  
  184.     init_text_buffer(&text_info->text);
  185.     text_info->max_width      = 0;
  186.     text_info->extra_width    = 0;
  187.     text_info->extra_height   = 0;
  188.     text_info->blocked          = FALSE;
  189.     text_info->destroy_on_ack = TRUE;    /* Ok to destroy before display */
  190.  
  191.     num_args = 0;
  192.     XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
  193.  
  194. #ifdef TRANSIENT_TEXT
  195.     wp->popup = XtCreatePopupShell("text", transientShellWidgetClass,
  196.                    toplevel, args, num_args);
  197. #else
  198.     wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass,
  199.                    toplevel, args, num_args);
  200. #endif
  201.  
  202.     num_args = 0;
  203.     XtSetArg(args[num_args], XtNdisplayCaret, False);        num_args++;
  204.     XtSetArg(args[num_args], XtNresize, XawtextResizeBoth);    num_args++;
  205.     XtSetArg(args[num_args], XtNtranslations,
  206.         XtParseTranslationTable(text_translations));    num_args++;
  207.  
  208.     wp->w = XtCreateManagedWidget(
  209.         killer && WIN_MAP == WIN_ERR ?
  210.                   "tombstone" : "text_text", /* name */
  211.         asciiTextWidgetClass,
  212.         wp->popup,        /* parent widget */
  213.         args,            /* set some values */
  214.         num_args);        /* number of values to set */
  215.  
  216.     /* Get the font and margin information. */
  217.     num_args = 0;
  218.     XtSetArg(args[num_args], XtNfont,          &text_info->fs); num_args++;
  219.     XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
  220.     XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
  221.     XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
  222.     XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
  223.     XtGetValues(wp->w, args, num_args);
  224.  
  225.     text_info->extra_width  = left_margin + right_margin;
  226.     text_info->extra_height = top_margin + bottom_margin;
  227. }
  228.  
  229. void
  230. destroy_text_window(wp)
  231.     struct xwindow *wp;
  232. {
  233.     /* Don't need to pop down, this only called from dismiss_text(). */
  234.  
  235.     struct text_info_t *text_info = wp->text_information;
  236.  
  237.     /*
  238.      * If the text window was blocked, then the user has already ACK'ed
  239.      * it and we are free to really destroy the window.  Otherwise, don't
  240.      * destroy until the user dismisses the window via a key or button
  241.      * press.
  242.      */
  243.     if (text_info->blocked || text_info->destroy_on_ack) {
  244.     XtDestroyWidget(wp->popup);
  245.     free_text_buffer(&text_info->text);
  246.     free((char *) text_info);
  247.     wp->type = NHW_NONE;    /* allow reuse */
  248.     } else {
  249.     text_info->destroy_on_ack = TRUE;    /* destroy on next ACK */
  250.     }
  251. }
  252.  
  253.  
  254. /* text buffer routines ---------------------------------------------------- */
  255.  
  256. /* Append a line to the text buffer. */
  257. void
  258. append_text_buffer(tb, str, concat)
  259.     struct text_buffer *tb;
  260.     const char *str;
  261.     boolean concat;
  262. {
  263.     char *copy;
  264.     int length;
  265.  
  266.     if (!tb->text) panic("append_text_buffer:  null text buffer");
  267.  
  268.     if (str) {
  269.         length = strlen(str);
  270.     } else {
  271.     length = 0;
  272.     }
  273.  
  274.     if (length + tb->text_last + 1 >= tb->text_size) {
  275.     /* we need to go to a bigger buffer! */
  276. #ifdef VERBOSE
  277.     printf("append_text_buffer: text buffer growing from %d to %d bytes\n",
  278.                 tb->text_size, 2*tb->text_size);
  279. #endif
  280.     copy = (char *) alloc(tb->text_size*2);
  281.     (void) memcpy(copy, tb->text, tb->text_last);
  282.     free(tb->text);
  283.     tb->text = copy;
  284.     tb->text_size *= 2;
  285.     }
  286.  
  287.     if (tb->num_lines) {    /* not first --- append a newline */
  288.     char appchar = '\n';
  289.  
  290.     if(concat && !index("!.?'\")", tb->text[tb->text_last-1])) {
  291.         appchar = ' ';
  292.         tb->num_lines--; /* offset increment at end of function */
  293.     }
  294.  
  295.     *(tb->text + tb->text_last) = appchar;
  296.     tb->text_last++;
  297.     }
  298.  
  299.     if (str) {
  300.     (void) memcpy((tb->text+tb->text_last), str, length+1);
  301.     if(length) {
  302.         /* Remove all newlines. Otherwise we have a confused line count. */
  303.         copy = (tb->text+tb->text_last);
  304.         while (copy = index(copy, '\n'))
  305.         *copy = ' ';
  306.     }
  307.  
  308.     tb->text_last += length;
  309.     }
  310.     tb->text[tb->text_last] = '\0';
  311.     tb->num_lines++;
  312. }
  313.  
  314. /* Initialize text buffer. */
  315. void
  316. init_text_buffer(tb)
  317.     struct text_buffer *tb;
  318. {
  319.     tb->text      = (char *) alloc(START_SIZE);
  320.     tb->text[0]   = '\0';
  321.     tb->text_size = START_SIZE;
  322.     tb->text_last = 0;
  323.     tb->num_lines = 0;
  324. }
  325.  
  326. /* Empty the text buffer */
  327. void
  328. clear_text_buffer(tb)
  329.     struct text_buffer *tb;
  330. {
  331.     tb->text_last = 0;
  332.     tb->text[0]   = '\0';
  333.     tb->num_lines = 0;
  334. }
  335.  
  336. /* Free up allocated memory. */
  337. void
  338. free_text_buffer(tb)
  339.     struct text_buffer *tb;
  340. {
  341.     free(tb->text);
  342.     tb->text = (char *) 0;
  343.     tb->text_size = 0;
  344.     tb->text_last = 0;
  345.     tb->num_lines = 0;
  346. }
  347.